{% load staticfiles %}

<script type="text/javascript">
	/*
	  Main resources: 
	  https://www.youtube.com/watch?v=cKIG1lKwLeo&t=401s&ab_channel=HongLy
	  For the ground zero code, see the exported files from here: 
	  https://codepen.io/mikewesthad/pen/BVeoYP?editors=1111 

	  Also worth taking a look: 
	  https://www.youtube.com/watch?v=fdXcD9X4NrQ&ab_channel=MorganPage
	  and 
	  https://www.youtube.com/watch?v=MR2CvWxOEsw&ab_channel=MattWilber
	 */


	// ###########################################################################
	// PREAMBLE
	// ###########################################################################

	// Phaser 3.0 global settings. 
	// Configuration meant to be passed to the main Phaser game instance. 
	const config = {
	  type: Phaser.AUTO,
	  width: 1500,
	  height: 800,
	  parent: "game-container",
	  pixelArt: true,
	  physics: {
	    default: "arcade",
	    arcade: {
	      gravity: { y: 0 } } },
	  scene: {
	    preload: preload,
	    create: create,
	    update: update } };

	// Creating the game instance and setting up the main Phaser variables that  
	// will be used in it. 
	const game = new Phaser.Game(config);
	let cursors;
	let player;
	let showDebug = false;

	// Persona related variables. This should have the name of the persona as its 
	// keys, and the instances of the Persona class as the values.
	var spawn_tile_loc = {};
	var personas = {};
	var pronunciatios = {};
	let anims_direction;
	let pre_anims_direction;

	let curr_maze = "the_ville";

	// <tile_width> is the width of one individual tile (tiles are square)
	let tile_width = 32;
	// Important: tile_width % movement_speed has to be 0. 
	// <movement_speed> determines how fast we move at each upate cylce. 
	let movement_speed = 32; 

	// <timer_max> determines how frequently our update function will query the 
	// frontend server. If it's higher, we wait longer cycles. 
	let timer_max = 0;
	let timer = timer_max;

	// <phase> -- there are three phases: "process," "update," and "execute."
	let phase = "update"; // or "update" or "execute"

	// Variables for storing movements that are sent from the backend server.
	let execute_movement;
	let execute_count_max = tile_width/movement_speed;
	let execute_count = execute_count_max;
	let movement_target = {};

	// <step> -- one full loop around all three phases determined by <phase> is 
	// a step. We use this to link the steps in the backend. 
	let step = parseInt(document.getElementById('step').innerHTML);
	let sim_code = document.getElementById('sim_code').innerHTML;

	// ###########################################################################
	// ENGINE
	// ###########################################################################

	// Joon: Phaser 3.0 is oriented around "scenes" -- recall how Pokemon plays: 
	//       there is the outdoor space, and then there is the indoor space; when
	//       you go inside, you transition to a new "scene" and the outdoor space
	//       basically disappears. 
	//       A scene in Phaser has four key methods that are called at different
	//       stages of rendering for different purposes. They are: 
	//       init() -> preload() -> create() -> update()
	//         init() is called only once at the very beginning. This is the 
	//           initialization function in case that is needed. 
	//         preload() is called once and preloads any of the assets
	//         create() is also called once after preloading... creates sprites 
	//           and actually displays stuff
	//         update() is called on each frame during the game play 

	function preload() {  
	  // Loading the necessary images (e.g., the background image, character 
	  // sprites). 

	  // Joon: for load.image, the first parameter is simply the key value that
	  //       you are passing in. The second parameter should be pointed to the
	  //       png file that contains the tileset. 
	  //       Also IMPORTANT: when you create a tileset in Tiled, always be  
	  //       sure to check the "embedded" option. 
	  this.load.image("blocks_1", "{% static 'assets/the_ville/visuals/map_assets/blocks/blocks_1.png' %}");
	  this.load.image("walls", "{% static 'assets/the_ville/visuals/map_assets/v1/Room_Builder_32x32.png' %}");
	  this.load.image("interiors_pt1", "{% static 'assets/the_ville/visuals/map_assets/v1/interiors_pt1.png' %}");
	  this.load.image("interiors_pt2", "{% static 'assets/the_ville/visuals/map_assets/v1/interiors_pt2.png' %}");
	  this.load.image("interiors_pt3", "{% static 'assets/the_ville/visuals/map_assets/v1/interiors_pt3.png' %}");
	  this.load.image("interiors_pt4", "{% static 'assets/the_ville/visuals/map_assets/v1/interiors_pt4.png' %}");
	  this.load.image("interiors_pt5", "{% static 'assets/the_ville/visuals/map_assets/v1/interiors_pt5.png' %}");
	  this.load.image("CuteRPG_Field_B", "{% static 'assets/the_ville/visuals/map_assets/cute_rpg_word_VXAce/tilesets/CuteRPG_Field_B.png' %}");
	  this.load.image("CuteRPG_Field_C", "{% static 'assets/the_ville/visuals/map_assets/cute_rpg_word_VXAce/tilesets/CuteRPG_Field_C.png' %}");
	  this.load.image("CuteRPG_Harbor_C", "{% static 'assets/the_ville/visuals/map_assets/cute_rpg_word_VXAce/tilesets/CuteRPG_Harbor_C.png' %}");
	  this.load.image("CuteRPG_Village_B", "{% static 'assets/the_ville/visuals/map_assets/cute_rpg_word_VXAce/tilesets/CuteRPG_Village_B.png' %}");
	  this.load.image("CuteRPG_Forest_B", "{% static 'assets/the_ville/visuals/map_assets/cute_rpg_word_VXAce/tilesets/CuteRPG_Forest_B.png' %}");
	  this.load.image("CuteRPG_Desert_C", "{% static 'assets/the_ville/visuals/map_assets/cute_rpg_word_VXAce/tilesets/CuteRPG_Desert_C.png' %}");
	  this.load.image("CuteRPG_Mountains_B", "{% static 'assets/the_ville/visuals/map_assets/cute_rpg_word_VXAce/tilesets/CuteRPG_Mountains_B.png' %}");
	  this.load.image("CuteRPG_Desert_B", "{% static 'assets/the_ville/visuals/map_assets/cute_rpg_word_VXAce/tilesets/CuteRPG_Desert_B.png' %}");
	  this.load.image("CuteRPG_Forest_C", "{% static 'assets/the_ville/visuals/map_assets/cute_rpg_word_VXAce/tilesets/CuteRPG_Forest_C.png' %}");

	  // Joon: This is the export json file you get from Tiled. 
	  this.load.tilemapTiledJSON("map", "{% static 'assets/the_ville/visuals/the_ville_jan7.json' %}");

	  // An atlas is a way to pack multiple images together into one texture. I'm 
	  // using it to load all the player animations (walking left, walking right, 
	  // etc.) in one image. For more info see:
	  // https://labs.phaser.io/view.html?src=src/animation/texture%20atlas%20animation.js
	  // If you don't use an atlas, you can do the same thing with a spritesheet, 
	  // see: https://labs.phaser.io/view.html?src=src/animation/single%20sprite%20sheet.js
	  // Joon: Technically, I think this guy had the best tutorial for atlas: 
	  //       https://www.youtube.com/watch?v=fdXcD9X4NrQ&ab_channel=MorganPage
	  this.load.atlas("atlas", 
	                  "https://mikewesthad.github.io/phaser-3-tilemap-blog-posts/post-1/assets/atlas/atlas.png", 
	                  "https://mikewesthad.github.io/phaser-3-tilemap-blog-posts/post-1/assets/atlas/atlas.json");
	}

	function create() {  
	  const map = this.make.tilemap({ key: "map" });
	  // Joon: Logging map is really helpful for debugging here: 
	  //       console.log(map);

	  // The first parameter is the name you gave to the tileset in Tiled and then
	  // the key of the tileset image in Phaser's cache (i.e. the name you used in
	  // preload)
	  // Joon: for the first parameter here, really take a look at the 
	  //       console.log(map) output. You need to make sure that the name 
	  //       matches.
	  const collisions = map.addTilesetImage("blocks", "blocks_1");
	  const walls = map.addTilesetImage("Room_Builder_32x32", "walls");
	  const interiors_pt1 = map.addTilesetImage("interiors_pt1", "interiors_pt1");
	  const interiors_pt2 = map.addTilesetImage("interiors_pt2", "interiors_pt2");
	  const interiors_pt3 = map.addTilesetImage("interiors_pt3", "interiors_pt3");
	  const interiors_pt4 = map.addTilesetImage("interiors_pt4", "interiors_pt4");
	  const interiors_pt5 = map.addTilesetImage("interiors_pt5", "interiors_pt5");
	  const CuteRPG_Field_B = map.addTilesetImage("CuteRPG_Field_B", "CuteRPG_Field_B");
	  const CuteRPG_Field_C = map.addTilesetImage("CuteRPG_Field_C", "CuteRPG_Field_C");
	  const CuteRPG_Harbor_C = map.addTilesetImage("CuteRPG_Harbor_C", "CuteRPG_Harbor_C");
	  const CuteRPG_Village_B = map.addTilesetImage("CuteRPG_Village_B", "CuteRPG_Village_B");
	  const CuteRPG_Forest_B = map.addTilesetImage("CuteRPG_Forest_B", "CuteRPG_Forest_B");
	  const CuteRPG_Desert_C = map.addTilesetImage("CuteRPG_Desert_C", "CuteRPG_Desert_C");
	  const CuteRPG_Mountains_B = map.addTilesetImage("CuteRPG_Mountains_B", "CuteRPG_Mountains_B");
	  const CuteRPG_Desert_B = map.addTilesetImage("CuteRPG_Desert_B", "CuteRPG_Desert_B");
	  const CuteRPG_Forest_C = map.addTilesetImage("CuteRPG_Forest_C", "CuteRPG_Forest_C");

	  // The first parameter is the layer name (or index) taken from Tiled, the 
	  // second parameter is the tileset you set above, and the final two 
	  // parameters are the x, y coordinate. 
	  // Joon: The "layer name" that comes as the first parameter value  
	  //       literally is taken from our Tiled layer name. So to find out what
	  //       they are; you actually need to open up tiled and see how you 
	  //       named things there. 
	  let tileset_group_1 = [CuteRPG_Field_B, CuteRPG_Field_C, CuteRPG_Harbor_C, CuteRPG_Village_B, 
	  											 CuteRPG_Forest_B, CuteRPG_Desert_C, CuteRPG_Mountains_B, CuteRPG_Desert_B, CuteRPG_Forest_C,
	  											 interiors_pt1, interiors_pt2, interiors_pt3, interiors_pt4, interiors_pt5, walls];
	  const bottomGroundLayer = map.createLayer("Bottom Ground", tileset_group_1, 0, 0);
	  const exteriorGroundLayer = map.createLayer("Exterior Ground", tileset_group_1, 0, 0);
	  const exteriorDecorationL1Layer = map.createLayer("Exterior Decoration L1", tileset_group_1, 0, 0);
	  const exteriorDecorationL2Layer = map.createLayer("Exterior Decoration L2", tileset_group_1, 0, 0);
	  const interiorGroundLayer = map.createLayer("Interior Ground", tileset_group_1, 0, 0);
	  const wallLayer = map.createLayer("Wall", [CuteRPG_Field_C, walls], 0, 0);
	  const interiorFurnitureL1Layer = map.createLayer("Interior Furniture L1", tileset_group_1, 0, 0);
	  const interiorFurnitureL2Layer = map.createLayer("Interior Furniture L2 ", tileset_group_1, 0, 0);
	  const foregroundL1Layer = map.createLayer("Foreground L1", tileset_group_1, 0, 0);
	  const foregroundL2Layer = map.createLayer("Foreground L2", tileset_group_1, 0, 0);
	  foregroundL1Layer.setDepth(2);
	  foregroundL2Layer.setDepth(2);

	  const collisionsLayer = map.createLayer("Collisions", collisions, 0, 0);
	  // const groundLayer = map.createLayer("Ground", walls, 0, 0);
	  // const indoorGroundLayer = map.createLayer("Indoor Ground", walls, 0, 0);
	  // const wallsLayer = map.createLayer("Walls", walls, 0, 0);
	  // const interiorsLayer = map.createLayer("Furnitures", interiors, 0, 0);
	  // const builtInLayer = map.createLayer("Built-ins", interiors, 0, 0);
	  // const appliancesLayer = map.createLayer("Appliances", interiors, 0, 0);
	  // const foregroundLayer = map.createLayer("Foreground", interiors, 0, 0);

	  // Joon : This is where you want to create a custom field for the tileset
	  //        in Tiled. Take a look at this guy's tutorial: 
	  //        https://www.youtube.com/watch?v=MR2CvWxOEsw&ab_channel=MattWilber
	  collisionsLayer.setCollisionByProperty({ collide: true });
	  // By default, everything gets depth sorted on the screen in the order we 
	  // created things. Here, we want the "Above Player" layer to sit on top of 
	  // the player, so we explicitly give it a depth. Higher depths will sit on 
	  // top of lower depth objects.
	  // Collisions layer should get a negative depth since we do not want to see
	  // it. 
	  collisionsLayer.setDepth(1);

	  // *** SET UP CAMERA *** 
	  // "player" is to be set as the center of mass for our "camera." We 
	  // basically create a game character sprite as we would for our personas 
	  // but we move it to depth -1 and let it pass through the collision map;  
	  // that is, do not have the following line: 
	  // this.physics.add.collider(player, collisionsLayer);
	  // OLD NOTE: Create a sprite with physics enabled via the physics system. 
	  // The image  used for the sprite has a bit of whitespace, so I'm using 
	  // setSize & setOffset to control the size of the player's body.
	  player = this.physics.add.
	                sprite(1856, 288, "atlas", "misa-front").
	                setSize(30, 40).
	                setOffset(0, 0);
	  player.setDepth(1);
	  // Setting up the camera. 
	  const camera = this.cameras.main;
	  camera.startFollow(player);
	  camera.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
	  cursors = this.input.keyboard.createCursorKeys();

	  // *** SET UP PERSONAS *** 
	  // We start by creating the game sprite objects. 
	  for (let i=0; i<Object.keys(spawn_tile_loc).length; i++) { 
	    let persona_name = Object.keys(spawn_tile_loc)[i];
	    let start_pos = [spawn_tile_loc[persona_name][0] * tile_width + tile_width / 2, 
	                     spawn_tile_loc[persona_name][1] * tile_width + tile_width];
	    let new_sprite = this.physics.add
	                         .sprite(start_pos[0], start_pos[1], "atlas", "misa-front")
	                         .setSize(30, 40)
	                         .setOffset(0, 0);
	    // Here, we are creating the persona and its pronunciatio sprites.
	    personas[persona_name] = new_sprite;
	    pronunciatios[persona_name] = this.add.text(
	                                   new_sprite.body.x - 6, 
	                                   new_sprite.body.y - 42, 
	                                   "🦁", {
	                                   font: "28px monospace", 
	                                   fill: "#000000", 
	                                   padding: { x: 8, y: 8}, 
	                                   backgroundColor: "#ffffff",
	                                   border:"solid",
	                                   borderRadius:"10px"});;
	  }

	  // Create the player's walking animations from the texture atlas. These are
	  // stored in the global animation manager so any sprite can access them.
	  const anims = this.anims;
	  anims.create({
	    key: "misa-left-walk",
	    frames: anims.generateFrameNames("atlas", { prefix: "misa-left-walk.", start: 0, end: 3, zeroPad: 3 }),
	    frameRate: 4,
	    repeat: -1 });

	  anims.create({
	    key: "misa-right-walk",
	    frames: anims.generateFrameNames("atlas", { prefix: "misa-right-walk.", start: 0, end: 3, zeroPad: 3 }),
	    frameRate: 4,
	    repeat: -1 });

	  anims.create({
	    key: "misa-front-walk",
	    frames: anims.generateFrameNames("atlas", { prefix: "misa-front-walk.", start: 0, end: 3, zeroPad: 3 }),
	    frameRate: 4,
	    repeat: -1 });

	  anims.create({
	    key: "misa-back-walk",
	    frames: anims.generateFrameNames("atlas", { prefix: "misa-back-walk.", start: 0, end: 3, zeroPad: 3 }),
	    frameRate: 4,
	    repeat: -1 });
	}


	function update(time, delta) {
	  // *** MOVE CAMERA *** 
	  // This is where we finish up the camera setting we started in the create() 
	  // function. We set the movement speed of the camera and wire up the keys to
	  // map to the actual movement.
	  const camera_speed = 400;
	  // Stop any previous movement from the last frame
	  player.body.setVelocity(0);
	  if (cursors.left.isDown) {
	    player.body.setVelocityX(-camera_speed);
	  } 
	  if (cursors.right.isDown) {
	    player.body.setVelocityX(camera_speed);
	  } 
	  if (cursors.up.isDown) {
	    player.body.setVelocityY(-camera_speed);
	  } 
	  if (cursors.down.isDown) {
	    player.body.setVelocityY(camera_speed);
	  }

	  // console.log("phase: " + phase + ", step: " + step);
	  // *** MOVE PERSONAS ***
	  // Moving personas take place in three distinct phases: "process," "update,"
	  // and "execute." These phases are determined by the value of <phase>. 
	  // Only one of the three phases is incurred in each update cycle. 
    let data = {"camera": {"maze": curr_maze,
    											 "x": player.body.position.x, 
    											 "y": player.body.position.y}}
    var json = JSON.stringify(data);
    // We then send this to the frontend server: 
    var retrieve_xobj = new XMLHttpRequest();
    retrieve_xobj.overrideMimeType("application/json");
    retrieve_xobj.open('POST', "{% url 'path_tester_update' %}", true);
    retrieve_xobj.send(json);   
    // Finally, we update the phase variable to start the "udpate" process. 
    // Now that we sent all persona locations to the backend server, we need
    // to wait until the backend determines what the personas will do next. 
    phase = "update";
	}

	// Control button binders
	var play_button=document.getElementById("play_button");
	var pause_button=document.getElementById("pause_button");
</script>







